package com.parsechina.hpush.broker.spi;

import com.parsechina.hpush.broker.internal.ClientSession;
import com.parsechina.hpush.broker.internal.MessageGUID;
import com.parsechina.hpush.broker.internal.StoredMessage;
import com.parsechina.hpush.broker.internal.subscriptions.Subscription;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * session存储接口
 *
 * @author linfeng
 */
public interface ISessionsStore {

    class ClientTopicRelation {
        public final String topicFilter;
        public final String clientId;

        public ClientTopicRelation(String clientId, String topicFilter) {
            this.clientId = clientId;
            this.topicFilter = topicFilter;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ClientTopicRelation that = (ClientTopicRelation) o;
            return Objects.equals(topicFilter, that.topicFilter) &&
                    Objects.equals(clientId, that.clientId);
        }

        @Override
        public int hashCode() {
            return Objects.hash(topicFilter, clientId);
        }

        @Override
        public String toString() {
            return "ClientTopicCouple{" +
                    "topicFilter='" + topicFilter + '\'' +
                    ", clientId='" + clientId + '\'' +
                    '}';
        }
    }

    /**
     * 初始化存储
     */
    void initStore();

    /**
     * 更新清除状态
     * @param clientId 客户端ID
     * @param cleanSession 是否清除session
     */
    void updateCleanStatus(String clientId, boolean cleanSession);

    /**
     * 添加新的订阅信息到session
     * @param newSubscription 新的订阅信息
     */
    void addNewSubscription(Subscription newSubscription);


    /**
     * 删除一个指定的 subscription
     * @param topic 主题
     * @param clientId 客户端ID
     */
    void removeSubscription(String topic, String clientId);


    /**
     * Remove all the subscriptions of the session
     * @param clientId 客户端ID
     */
    void removeAllSubscriptions(String clientId);


    /**
     * Return all topic filters to recreate the subscription tree.
     * @return client topic relation list
     */
    List<ClientTopicRelation> listAllSubscriptions();


    /**
     * 根据client 和 topic查询出 subscription
     * @param relation 关系
     * @return the subscription stored by clientId and topicFilter, if any else null;
     */
    Subscription getSubscription(ClientTopicRelation relation);


    /**
     * 返回订阅信息list
     * @return all subscriptions stored.
     */
    List<Subscription> getSubscriptions();

    /**
     *
     * @return true if there are subscriptions persisted with clientId
     */
    boolean contains(String clientId);

    /**
     * 创建 新的客户端session
     * @param clientId 客户端ID
     * @param cleanSession 是否清除session
     * @return 客户端 session
     */
    ClientSession createNewSession(String clientId, boolean cleanSession);

    /**
     * 查询客户端 session 根据clientId查询
     * @param clientId the client owning the session.
     * @return the session for the given clientId, null if not found.
     * */
    ClientSession sessionForClient(String clientId);

    /**
     * 根据clientId删除session
     * @param clientId 客户端ID
     */
    void removeSessionOfClient(String clientId);

    MessageGUID inFlightAck(String clientId, int messageId);

    /**
     * Save the binding messageID, clientId <-> guid
     * */
    void inFlight(String clientId, int messageId, MessageGUID guid);

    /**
     * Return the next valid packetIdentifier for the given client session.
     * */
    int nextPacketId(String clientId);

    /**
     * Store the guid to be later published.
     * */
    void bindToDeliver(MessageGUID guid, String clientId);

    /**
     * List the guids for retained messages for the session
     * */
    Collection<MessageGUID> enqueued(String clientId);

    void removeMessageGUID(String clientId, int messageId, MessageGUID guid);

    /**
     * Remove form the queue of stored messages for session.
     * */
    void removeEnqueued(String clientId, int messageId, MessageGUID guid);

    void moveInFlightToSecondPhaseAckWaiting(String clientId, int messageId);

    /**
     * 删除缓存的信息然后返回
     * @return the guid of message just acked.
     * */
    MessageGUID secondPhaseAcknowledged(String clientId, int messageId);

    MessageGUID mapToGuid(String clientId, int messageId);

    StoredMessage getInflightMessage(String clientId, int messageId);

}
